//
//  main.m
//  FilePermutator
//
//  Created by Christopher Kemsley on 4/7/12.
//  Copyright (c) 2012 iAppolopolis. All rights reserved.
//

#import <Foundation/Foundation.h>
#import "Permutator.h"






@interface Main : NSObject {
	NSString		*	inputPath ;
	NSString		*	outputPath ;
	
	NSArray			*	inputDirectories ;
	Permutator		*	permutator ;
}

+ (void)	raise:(NSString*)domain reason:(NSString*)format,... ;

- (id)		initWithArgc:(int)argc argv:(char const*const*)argv ;
- (void)	run ;

@end






@implementation	Main


#pragma mark	-	Main run entry point

- (id)		initWithArgc:(int)argc argv:(char const*const*)argv {
	if ( (self = [super init]) )
		{
		if ( argc != 3 )
			{
			[Main raise:NSInvalidArgumentException reason:@"Incorrect argument count. Usage: FilePermutator <inputPath> <outputPath>"] ;
			}
		
		
		/** Get the arguments **/
		inputPath	=	[NSString stringWithCString:argv[1] encoding:NSASCIIStringEncoding] ;
		outputPath	=	[NSString stringWithCString:argv[2] encoding:NSASCIIStringEncoding] ;
		}
	return self ;
}

- (void)	run {
	/** Get the input files **/
	NSFileManager	*	manager		=	[ [NSFileManager alloc] init ] ;
	
	[manager changeCurrentDirectoryPath:inputPath] ;
	
	
	
	[self scanTopLevelDirectoryContents] ;
	[self scanSubdirectoriesAndFiles] ;
	[self expandPermutations] ;
}




#pragma mark	-	Workers

- (void)	scanTopLevelDirectoryContents {
	inputDirectories		=	[Main contentsOfDirectoryAtPath:inputPath] ;
	
	if ( inputDirectories.count==0 )
		[Main raise:NSGenericException reason:@"Failed to load directory contents of '%@' - error: no non-hidden files/folders",inputPath] ;
}
- (void)	scanSubdirectoriesAndFiles {
	NSFileManager	*	manager		=	[NSFileManager defaultManager] ;
	NSMutableArray	*	allEntries	=	[NSMutableArray arrayWithCapacity:inputDirectories.count] ;
	
	for ( NSString * itemName in inputDirectories )
		{
		NSString	*	itemPath	=	[inputPath stringByAppendingPathComponent:itemName] ;
		
		BOOL			isDir		=	NO ;
		[manager fileExistsAtPath:itemPath isDirectory:&isDir] ;
		
		NSArray		*	entryFiles ;
		
		if ( isDir )
			{
			NSArray			*	array		=	[Main contentsOfDirectoryAtPath:itemPath] ;
			NSMutableArray	*	paths		=	[NSMutableArray arrayWithCapacity:array.count] ;
			for ( NSString * subitemName in array )
				{
				NSString	*	subitemPath	=	[itemPath stringByAppendingPathComponent:subitemName] ;
				PermutatorFile * file = [ [PermutatorFile alloc] initWithName:subitemName path:subitemPath ] ;
				[paths addObject:file] ;
				}
			entryFiles = paths ;
			}
		else
			{
			PermutatorFile * file = [ [PermutatorFile alloc] initWithName:itemName path:itemPath ] ;
			entryFiles = [NSArray arrayWithObject:file] ;
			}
		
		PermutatorEntry		*	entry	=	[ [PermutatorEntry alloc] initWithName:itemName files:entryFiles ] ;
		[allEntries addObject:entry] ;
		}
	
	permutator = [ [Permutator alloc] initWithEntries:allEntries ] ;
}
- (void)	expandPermutations {
	NSError			*	error	=	0 ;
	NSFileManager	*	manager	=	[NSFileManager defaultManager] ;
	
	[manager removeItemAtPath:outputPath error:nil] ;
	[manager createDirectoryAtPath:outputPath withIntermediateDirectories:YES attributes:nil error:&error] ;
	
	if ( error != 0 ) [Main raise:NSGenericException reason:@"Failed to create output directory: %@",error] ;
	
	NSUInteger			index	=	0 ;
	
	PermutatorEnumerator	*	e	=	[ [PermutatorEnumerator alloc] initWithPermutator:permutator ] ;
	for ( NSArray * files in [e allPermutations] )
		{
		NSString	*	dirName		=	[NSString stringWithFormat:@"Permutation%u",(unsigned)index++] ;
		NSString	*	dirPath		=	[outputPath stringByAppendingPathComponent:dirName] ;
		
		/* Create its directory */
		[manager createDirectoryAtPath:dirPath withIntermediateDirectories:NO attributes:nil error:&error] ;
		if ( error != 0 ) [Main raise:NSGenericException reason:@"Failed to create output sub-directory: %@",error] ;
		
		NSMutableString * metadata = [NSMutableString stringWithString:@"This permutation is made from:"] ;
		
		/* Copy the files */
		for ( PermutatorFile * file in files )
			{
			[metadata appendFormat:@"\n%@ = %@",file.parent.name,file.name] ;
			NSString*	destPath	=	[dirPath stringByAppendingPathComponent:file.parent.name] ;
			[manager copyItemAtPath:file.path toPath:destPath error:&error] ;
			if ( error != 0 ) [Main raise:NSGenericException reason:@"Failed to copy permutation file %@: %@",file.name,error] ;
			}
		
		NSString * metadataPath = [dirPath stringByAppendingPathComponent:@"PermutationInformation.txt"] ;
		[metadata writeToFile:metadataPath atomically:YES encoding:NSASCIIStringEncoding error:nil] ;
		}
}



#pragma mark	-	Utilities

+ (void)	raise:(NSString*)name reason:(NSString*)format,... {
	va_list	l ;
	va_start ( l , format ) ;
	NSString * reason = [ [NSString alloc] initWithFormat:format arguments:l ] ;
	NSException * e = [NSException exceptionWithName:name reason:reason userInfo:nil] ;
	va_end(l) ;
	[e raise] ;
}
+ (NSArray*)	contentsOfDirectoryAtPath:(NSString*)path {
	NSError		*	error	=	0 ;
	NSArray		*	array	=	[ [NSFileManager defaultManager] contentsOfDirectoryAtPath:path error:&error] ;
	if ( error != 0 )
		[Main raise:NSGenericException reason:@"Error while getting contents of %@ -- %@",path,error] ;
	
	NSPredicate*	filter	=	[NSPredicate predicateWithBlock:^BOOL(id str,NSDictionary*b){
		return [str characterAtIndex:0] != '.' ;
	}] ;
	return [array filteredArrayUsingPredicate:filter] ;
}




#pragma mark	-	"main" redirect

+ (int)		startWithArgc:(int)argc argv:(char const*const*)argv {
	@try {
		Main * me = [ [Main alloc] initWithArgc:argc argv:argv ] ;
		[me run] ;
		return 0 ;
	} @catch ( NSException * e ) {
		NSLog ( @"Caught exception: %@" , e ) ;
		return -1 ;
	} @catch ( ... ) {
		NSLog ( @"Caught unknown exception" ) ;
		return -1 ;
	}
}

@end













int main(int argc, const char * argv[])
{
	@autoreleasepool
	{
	[Main startWithArgc:argc argv:argv] ;
	}
    return 0;
}

